home *** CD-ROM | disk | FTP | other *** search
- /*-----------------------------------------------------------------------------
-
- Generic LaserWriter.c
-
- This part of the driver demonstrates how to handle your own 'scan'
- resource processing.
-
- 12/18/93 - dmh - Removed IIg-dependencies for b3.
- 9/13/93 - dmh - Updated for the b2 seed.
- 9/14/93 - dmh - Disabled the PostScript log which was created in the
- Extensions folder.
- 3/22/94 - dmh - Balanced gxInitialize override with a gxShutDown one.
- 6/18/94 - dmh - Added 'scan' handling support.
- 7/04/94 - dmh - Changed 'scan' loading so that only one fetch is done
- for either pre-scan handle regardless of how many DTPs
- are printing, and how many gxPostScriptScanStatusText
- and gxPostScriptScanPrinterText messages are processed.
- Note that this code now uses both the driver's class
- and instance contexts to store data.
- 7/11/94 - dmh - Changed HandleScanning and the two GXScanXXXText
- routines so that if the text becomes empty after
- prescanning, we do not consider that a return to
- "normal" status and reset our alerts.
- 7/12/94 - dmh - Gack! Various uninitialized variables initialized.
- 6/14/96 - cn - Updated to support Universal Interfaces 2.1.
-
- © 1991-1996 Apple Computer Inc.
-
- -----------------------------------------------------------------------------*/
- #include "Generic LaserWriter.h"
-
- /* ______________________________________________________________
-
- DriverOpenConnection -
-
- This routine is an override for gxOpenConnection. It forwards
- the message and sets up our global data for the 'scan'
- handling code.
-
- WHY THIS IS IMPORTANT:
-
- The 'scan' handling code will rely on our global data for
- status handling state information.
-
- ______________________________________________________________ */
-
- OSErr DriverOpenConnection()
- {
- OSErr err;
-
- /*
- Forward the gxOpenConnection message, after setting up our class
- context and instance context data.
-
- (We'll store most of our globals in the driver's instance
- context, but we'll store the 'scan' handles in the driver's
- class context. This is because all instances of our driver
- can share the same 'scan' handles, so we can avoid
- duplication of data and wasted memory allocation.)
-
- If an error occurs, clean up after ourselves.
- */
- err = SetUpClassContextData();
- if (!err) err = SetUpInstanceContextData();
-
- if (err)
- {
- DisposeClassContextData();
- DisposeInstanceContextData();
- }
- else
- {
- err = Forward_GXOpenConnection();
- if (err) GXCleanupOpenConnection();
- }
-
- return err;
- }
-
-
- /* ______________________________________________________________
-
- DriverCleanupOpenConnection -
-
- This routine is an override for gxCleanupOpenConnection. It
- removes any data we allocated in DriverOpenConnection in the
- event that an error occurs and DriverCloseConnection isn't
- called. It's important to do this if you allocate data in a
- gxOpenConnection override and want to toss it when the
- connection closes.
-
- WHY THIS IS IMPORTANT:
-
- gxCleanupOpenConnection will be sent instead of
- gxCloseConnection if an error occurs after a successful open
- connection attempt.
-
- ______________________________________________________________ */
-
- void DriverCleanupOpenConnection()
- {
- /*
- Forward the message, then dispose of our class and instance
- context data. (We will only decrement the owner count of the
- class context data if we're not the last user.)
- */
- Forward_GXCleanupOpenConnection();
- DisposeClassContextData();
- DisposeInstanceContextData();
- }
-
-
- /* ______________________________________________________________
-
- DriverCloseConnection -
-
- This routine is an override for gxCloseConnection. After
- forwarding the message, it frees up our global data we stored
- in DriverOpenConnection.
-
- WHY THIS IS IMPORTANT:
-
- You should always clean up after yourself, so nobody will
- hurt themselves tripping over your junk.
-
- ______________________________________________________________ */
-
- OSErr DriverCloseConnection()
- {
- OSErr err;
- /*
- Forward the message, then dispose of our class and instance
- context data. (We will only decrement the owner count of the
- class context data if we're not the last user.)
- */
- err = Forward_GXCloseConnection();
- DisposeClassContextData();
- DisposeInstanceContextData();
-
- return err;
- }
-
-
- /* ______________________________________________________________
-
- SetUpClassContextData -
-
- This routine sets up the data for our class context, if it
- doesn't exist. If it already exists, we simply increment
- the owner count for our data. Otherwise, we create a handle
- for our data, set its owner count to 1, and store handles to
- the 'scan' resources we'll use in ScanText.
-
- WHY THIS IS IMPORTANT:
-
- By caching these resources now, we don't have to waste time
- disposing and reloading them each time we scan some text.
- And, since we're sharing these handles between instances of
- our driver, only one load of each resource will be performed,
- regardless of how many desktop printers are printing at once.
- These handles are eventually disposed of in the
- DriverCloseConnection routine.
-
- ______________________________________________________________ */
-
- OSErr SetUpClassContextData()
- {
- OSErr err = noErr;
- THz oldZone;
- DriverClassGlobalsHdl classGlobals;
-
- /*
- Get our current class context. If non-nil, it's a handle to our
- class context data. In that case, bump the owner count.
- Otherwise, the data hasn't been set up yet, so create a handle
- for our class context data, and set the owner count to 1.
- */
- classGlobals = (DriverClassGlobalsHdl) GetMessageHandlerClassContext();
- nrequire_action(classGlobals, ClassContextExists, ++(*classGlobals)->ownerCount;);
-
- classGlobals = (DriverClassGlobalsHdl) TempNewHandle(sizeof(DriverClassGlobals), &err);
- nrequire(err, MemoryError);
-
- (*classGlobals)->ownerCount = 1;
-
- /*
- Get the detached 'scan' resources for gxScanStatusText and
- gxScanPrinterText. Store these handles in our global data.
- Note that if a resources isn't found, then nil will be
- stored as its handle's value.
- */
- Send_GXFetchTaggedDriverData(gxPostscriptScanningType,
- kStatusTextScanResID,
- &(*classGlobals)->statusScanHdl);
-
- Send_GXFetchTaggedDriverData(gxPostscriptScanningType,
- kPrinterTextScanResID,
- &(*classGlobals)->printerScanHdl);
-
- /*
- Because HandleScanning requires a locked scan handle, we move
- the handles high and lock them here. Note that you could
- remove this dependency in HandleScanning and DecodeScanEntry
- at the expense of code readability. Also note that MoveHHi
- expects you to set the current zone to the handle's zone
- before calling it.
- */
- oldZone = GetZone();
-
- if ((*classGlobals)->statusScanHdl)
- {
- SetZone(HandleZone((*classGlobals)->statusScanHdl));
- MoveHHi((*classGlobals)->statusScanHdl);
- HLock((*classGlobals)->statusScanHdl);
- }
-
- if ((*classGlobals)->printerScanHdl)
- {
- SetZone(HandleZone((*classGlobals)->printerScanHdl));
- MoveHHi((*classGlobals)->printerScanHdl);
- HLock((*classGlobals)->printerScanHdl);
- }
-
- SetZone(oldZone);
-
-
- // Finally, store our data handle in the driver's class context.
-
- SetMessageHandlerClassContext(classGlobals);
-
- MemoryError:
- ClassContextExists:
- return err;
- }
-
-
- /* ______________________________________________________________
-
- DisposeClassContextData -
-
- This routine decrements the owner count of the data we stored
- in our class context, anbd disposes of the data if the owner
- count goes to zero.
-
- WHY THIS IS IMPORTANT:
-
- Since several instances of our driver may be using this class
- context data, we must maintain an owner count for it. When
- all instances are through using it, we dispose of the data.
- To be safe, you should always use an owner count for any data
- you store in a class context. As unlikely as it may seem,
- there's always the possibility that more than one instance of
- your handler can be accessing the class context data at a
- time, and it would be bad if you disposed of data that
- another instance is still using.
-
- ______________________________________________________________ */
-
- void DisposeClassContextData()
- {
- DriverClassGlobalsHdl classGlobals;
-
- /*
- Get our class context data and decrement the owner count. If
- the new owner count is zero, dispose of the data we stored in
- SetUpClassContextData. Otherwise, one of our instanciations
- is still using the data so leave it be.
- */
- classGlobals = (DriverClassGlobalsHdl) GetMessageHandlerClassContext();
- require(classGlobals, NoGlobalsSet);
-
- if (--(*classGlobals)->ownerCount == 0)
- {
- if ((*classGlobals)->statusScanHdl)
- DisposHandle((*classGlobals)->statusScanHdl);
-
- if ((*classGlobals)->printerScanHdl)
- DisposHandle((*classGlobals)->printerScanHdl);
-
- DisposHandle((Handle) classGlobals);
- SetMessageHandlerClassContext(nil);
- }
-
- NoGlobalsSet:;
- }
-
-
- /* ______________________________________________________________
-
- SetUpInstanceContextData -
-
- This routine fills in the handle we'll store in our class
- context. This involves setting up an owner count (initially
- set to 1), and storing handles to the 'scan' resources we'll
- use in ScanText.
-
- WHY THIS IS IMPORTANT:
-
- By caching these resources now, we don't have to waste time
- disposing and reloading them each time we scan some text.
- And, since we're sharing these handles between instances of
- our driver, only one load of each resource will be performed,
- regardless of how many desktop printers are printing at once.
- These handles are eventually disposed of in the
- DriverCloseConnection routine.
-
- ______________________________________________________________ */
-
- OSErr SetUpInstanceContextData()
- {
- OSErr err;
- DriverInstanceGlobalsHdl instanceGlobals;
-
- // Create and store our instance context data.
-
- instanceGlobals = (DriverInstanceGlobalsHdl) TempNewHandle(sizeof(DriverInstanceGlobals), &err);
- nrequire(err, Failed_NewGlobals);
- SetMessageHandlerInstanceContext((void *) instanceGlobals);
-
- (*instanceGlobals)->printStatus =
- (gxStatusRecord *) NewPtrSysClear(sizeof(gxStatusRecord) +gxDefaultStatusBufferSize -1L);
-
- nrequire((err = MemError()), Failed_NewStatusRec);
- StoreInstanceContextStrings(instanceGlobals);
-
- Failed_NewStatusRec:
- Failed_NewGlobals:
- return err;
- }
-
-
- /* ______________________________________________________________
-
- StoreInstanceContextStrings -
-
- This routine stores the current job's application, user,
- document and output printer names in our instance globals.
-
- WHY THIS IS IMPORTANT:
-
- By caching these values at gxOpenConnection time, we don't
- have to repeat this work in the 'scan' handling code.
-
- ______________________________________________________________ */
-
- void StoreInstanceContextStrings(DriverInstanceGlobalsHdl instanceGlobals)
- {
- OSErr err;
- long itemSize;
- gxJobInfo jobInfo;
- gxJob currentJob = GXGetJob();
-
- /*
- Get the current job's application, user, document
- and output printer names.
- */
- itemSize = sizeof(gxJobInfo);
- err = GetCollectionItem(GXGetJobCollection(currentJob),
- gxJobTag, gxPrintingTagID,
- &itemSize, &jobInfo);
-
- /*
- No job info? Use empty strings.
- Otherwise, move the strings to our instance data.
- */
- if (err != noErr)
- {
- (*instanceGlobals)->userName[0] =
- (*instanceGlobals)->appName[0] =
- (*instanceGlobals)->documentName[0] = (char) 0;
- }
- else
- {
- BlockMove(jobInfo.userName, (*instanceGlobals)->userName, (long) jobInfo.userName[0] +1);
- BlockMove(jobInfo.appName, (*instanceGlobals)->appName, (long) jobInfo.appName[0] +1);
- BlockMove(jobInfo.documentName, (*instanceGlobals)->documentName, (long) jobInfo.documentName[0] +1);
- }
-
- GXGetPrinterName(GXGetJobOutputPrinter(currentJob), (*instanceGlobals)->printerName);
- }
-
-
- /* ______________________________________________________________
-
- DisposeInstanceContextData -
-
- This routine disposes of the data we stored in our instance
- context.
-
- WHY THIS IS IMPORTANT:
-
- ditto.
-
- ______________________________________________________________ */
-
- void DisposeInstanceContextData()
- {
- DriverInstanceGlobalsHdl instanceGlobals;
-
- // Get our instance context data.
-
- instanceGlobals = (DriverInstanceGlobalsHdl) GetMessageHandlerInstanceContext();
- require(instanceGlobals, NoGlobalsSet);
-
- /*
- Dispose of our status record, which we allocated in
- SetUpInstanceContextData. Then, dispose of our data handle and
- set our instance context to nil, to "invalidate" it.
- */
- if ((*instanceGlobals)->printStatus)
- DisposePtr((Ptr) (*instanceGlobals)->printStatus);
-
- DisposHandle((Handle) instanceGlobals);
- SetMessageHandlerInstanceContext(nil);
-
- NoGlobalsSet:;
- }
-
-
- /* ______________________________________________________________
-
- DriverPostScriptScanPrinterText -
-
- This routine is an override for gxPostScriptScanPrinterText.
- By overriding this message, we can 'scan' the passed text
- ourselves before (or instead of) passing the text to GX's
- default implementation.
-
- WHY THIS IS IMPORTANT:
-
- This is how we will tap into the 'scan' mechanism and put up
- alerts or desktop printer messages based on our own criteria.
- That means that we aren't confined to only using the 'scan'
- mechanism for handling the predefined GX error conditions.
-
- ______________________________________________________________ */
-
- OSErr DriverPostScriptScanPrinterText(Handle textHdl)
- {
- OSErr err;
- Boolean alertedUser;
-
- // "Pre-scan" the text.
-
- err = ScanText(textHdl, kScanPrinterTextType, &alertedUser);
-
- /*
- Now do the "default" scanning, unless there's an error, we
- called GXAlertTheUser to post a message, or there's no text
- left to scan. This keeps our last alert or message displayed
- as long as we want, without the default implementation
- replacing it.
- */
- if (!err && !alertedUser && (*(long *) *textHdl != 0))
- err = Forward_GXPostScriptScanPrinterText(textHdl);
-
- return err;
- }
-
-
- /* ______________________________________________________________
-
- DriverPostScriptScanStatusText -
-
- This routine is an override for gxPostScriptScanStatusText.
- By overriding this message, we can 'scan' the passed text
- ourselves before (or instead of) passing the text to GX's
- default implementation.
-
- WHY THIS IS IMPORTANT:
-
- This is how we will tap into the 'scan' mechanism and put up
- alerts or desktop printer messages based on our own criteria.
- That means that we aren't confined to only using the 'scan'
- mechanism for handling the predefined GX error conditions.
-
- ______________________________________________________________ */
-
- OSErr DriverPostScriptScanStatusText(Handle textHdl)
- {
- OSErr err;
- Boolean alertedUser;
-
- // "Pre-scan" the text.
-
- err = ScanText(textHdl, kScanStatusTextType, &alertedUser);
-
- /*
- Now do the "default" scanning, unless there's an error, we
- called GXAlertTheUser to post a message, or there's no text
- left to scan. This keeps our last alert or message displayed
- as long as we want, without the default implementation
- replacing it.
- */
- if (!err && !alertedUser && (*(long *) *textHdl != 0))
- err = Forward_GXPostScriptScanStatusText(textHdl);
-
- return err;
- }
-
-
- /* ______________________________________________________________
-
- ScanText -
-
- This routine is called to start the scanning process for the
- text passed, using the 'scan' resource indicated. On return,
- alertedUser will be set to true if GXAlertTheUser has been
- called to post a message. This indicates that the relevant
- GXPostScriptScanXXXText message should not be forwarded, or
- the default implementation might replace our alert or message.
-
- WHY THIS IS IMPORTANT:
-
- This code calls HandleScanning, which applies our 'scan'
- resource to the text handle we're working on.
-
- ______________________________________________________________ */
-
- OSErr ScanText(Handle textHdl, char scanType, Boolean *alertedUser)
- {
- OSErr err = noErr;
- Handle scanHdl;
- DriverClassGlobalsHdl classDataHdl;
-
- /*
- Initially, assume that we won't alert the user.
-
- Get the driver's global data, then reference the
- indicated 'scan' handle.
- */
- *alertedUser = false;
- classDataHdl = (DriverClassGlobalsHdl) GetMessageHandlerClassContext();
- require(classDataHdl, NoGlobalsSet);
-
- scanHdl = (scanType == kScanStatusTextType)?
- (*classDataHdl)->statusScanHdl: (*classDataHdl)->printerScanHdl;
-
- require(scanHdl, ScanHandleIsNil);
-
- // Apply the 'scan' resource to the text.
-
- err = HandleScanning(textHdl, scanHdl, alertedUser);
-
- ScanHandleIsNil:
- NoGlobalsSet:
- return err;
- }
-
-
- /* ______________________________________________________________
-
- HandleScanning -
-
- This routine is the main controlling routine of the scanning
- process. On return, alertedUser will be set to true if
- GXAlertTheUser has been called to post a message. This
- indicates that the relevant GXPostScriptScanXXXText message
- should not be forwarded, or the default implementation might
- replace our alert or message.
-
- WHY THIS IS IMPORTANT:
-
- This code applies the settings in a 'scan' resource to the
- text passed.
-
- ______________________________________________________________ */
-
- OSErr HandleScanning(Handle textHdl, Handle scanHdl, Boolean *alertedUser)
- {
- OSErr err = noErr;
- Boolean found;
- Str255 searchString, replaceString;
- char *str1Ptr, *str2Ptr;
- short *scanPtr, priorStatusLevel, priorStatusIndex;
- short offsetType, actionType, statusIndex, statusLevel = Normal;
- long endOfData, searchStringLen, replaceStringLen;
- gxStatusRecord *statusPtr;
- DriverInstanceGlobalsHdl instanceStateHdl;
-
- /*
- The first long in the textHdl is the text length. If zero,
- don't scan. Otherwise, retrieve our driver's instance data,
- the previous status level and the previous 'stat' index.
- Next, reset the current status level to Normal. We will
- adjust this below, based on the result of our 'scan' handling.
- */
- require(*(long *) *textHdl, NoTextToScan);
-
- instanceStateHdl = (DriverInstanceGlobalsHdl) GetMessageHandlerInstanceContext();
- require(instanceStateHdl, NoGlobalsSet);
- statusPtr = (*instanceStateHdl)->printStatus;
- require(statusPtr, NoGlobalsSet);
-
- priorStatusLevel = (*instanceStateHdl)->statusLevel;
- priorStatusIndex = (*instanceStateHdl)->statusIndex;
- (*instanceStateHdl)->statusLevel = Normal;
-
- /*
- Calculate where the last byte of the 'scan' handle is,
- and move past the owner count in our 'scan' handle.
- */
- endOfData = (long) ((*scanHdl) +GetHandleSize(scanHdl));
- scanPtr = (short *) (*scanHdl +4L);
-
- /*
- While there are more 'scan' entries to process, decode
- them and pass the results to Munger.
- */
- do
- {
- str1Ptr = (char *) searchString;
- str2Ptr = (char *) replaceString;
-
- err = DecodeScanEntry(&scanPtr,
- &str1Ptr, &searchStringLen,
- &str2Ptr, &replaceStringLen,
- &offsetType, &actionType,
- &statusLevel, &statusIndex);
-
- nrequire(err, DecodeScanEntry_Failed);
-
- found = MungeTheText(offsetType, textHdl,
- str1Ptr, searchStringLen,
- str2Ptr, replaceStringLen);
-
- /*
- If Munger finds a match and the 'scan' entry's action
- is SimpleAction, and the status level of this entry is
- greater than the current level or this is exactly the
- status we found the last time we scanned, update the
- current status level and 'stat' index. This way, we
- only extract the most urgent SimpleAction for processing
- below.
- */
- if (found && (actionType == SimpleAction) &&
- ((statusLevel > (*instanceStateHdl)->statusLevel) ||
- ((statusLevel == priorStatusLevel) && (statusIndex == priorStatusIndex))))
- {
- (*instanceStateHdl)->statusLevel = statusLevel;
- (*instanceStateHdl)->statusIndex = statusIndex;
- }
- }
- while ((unsigned long) scanPtr < (unsigned long) endOfData);
-
- /*
- Display or clear any alerts and messages as necessary.
-
- NOTE:
- If you use any alerts which require special handling (such as
- aborting the print job if a cancel button is pressed) you'll
- need to check the status record's dialogResult and do the
- appropriate thing here.
- */
- switch ((*instanceStateHdl)->statusLevel)
- {
- case Normal: // Return status to normal.
- if (priorStatusLevel == NonFatalError && (*(long *) *textHdl != 0))
- err = SetAlertStatus(kPrescanStatResID, kPrinterIsReadyIndex);
- break;
-
- // Non fatal error. If this is different
- // than the currently posted non-fatal
- // alert (if any), clear the previous alert
- // before posting the new one. Indicate that
- case NonFatalError: // we have posted a message with GXAlertTheUser.
-
- if ((priorStatusLevel == NonFatalError) &&
- (priorStatusIndex != (*instanceStateHdl)->statusIndex))
- err = SetAlertStatus(kPrescanStatResID, kPrinterIsReadyIndex);
-
- if (!err)
- err = SetAlertStatus(kPrescanStatResID, (*instanceStateHdl)->statusIndex);
-
- *alertedUser = true;
- break;
-
- case FatalError: // Fatal error. Retrieve the error code.
- err = (*instanceStateHdl)->statusIndex;
- break;
- }
-
- DecodeScanEntry_Failed:
- NoGlobalsSet:
- NoTextToScan:
- return err;
- }
-
-
- /* ______________________________________________________________
-
- DecodeScanEntry -
-
- This routine parses one entry in a 'scan' resource and
- determines what it all means.
-
- WHY THIS IS IMPORTANT:
-
- This is the code that turns 'scan' handle mush into coherant
- data.
-
- ______________________________________________________________ */
-
- OSErr DecodeScanEntry(short **scanPtrHolder,
- char **str1Ptr, long *str1Len,
- char **str2Ptr, long *str2Len,
- short *offsetType, short *actionType,
- short *statusLevel, short *statusIndex)
- {
- OSErr err = noErr;
- DriverInstanceGlobalsHdl instanceStateHdl;
- long *whichLen;
- char parsePass, *whichString;
- short stringType, *scanPtr = *scanPtrHolder;
-
- // Retrieve our globals.
-
- instanceStateHdl = (DriverInstanceGlobalsHdl) GetMessageHandlerInstanceContext();
-
- for (parsePass = 0; parsePass < 2; parsePass++)
- {
- /*
- We make two passes through this loop, extracting the
- search string entry on the first pass, and the replacement
- string entry on the second.
- */
- whichLen = (parsePass == 0)? str1Len: str2Len;
- whichString = (parsePass == 0)? *str1Ptr: *str2Ptr;
-
- // Get the entry's string type and move past the word it occupied.
-
- stringType = *scanPtr;
- ++scanPtr;
-
- // Now extract any auxiliary data for this string type.
-
- switch (stringType)
- {
- /*
- SimpleScan entries have a length word followed by
- word-aligned string data. For these, get the length,
- move past that word, BlockMove the characters to our
- string, and update our scanPtr to the word after the
- last character (remember, it's word-aligned).
- */
- case SimpleScan:
- *whichLen = *scanPtr;
- ++scanPtr;
- BlockMove(scanPtr, whichString, (long) *whichLen);
- scanPtr = (short *) (((char *) scanPtr) + *whichLen + (*whichLen & 1L));
- break;
-
- /*
- UserNameScan, DocumentNameScan, and PrinterNameScan
- entries have no extra data, but we need to retrieve
- the requested information. We cached these strings
- earlier, so we just need to store the lengths and
- BlockMove the characters. Note that there's no extra
- data to move past, so we don't update the scanPtr.
- */
- case UserNameScan:
- *whichLen = (*instanceStateHdl)->userName[0];
- BlockMove(&(*instanceStateHdl)->userName[1], whichString, *whichLen);
- break;
-
- case DocumentNameScan:
- *whichLen = (*instanceStateHdl)->documentName[0];
- BlockMove(&(*instanceStateHdl)->documentName[1], whichString, *whichLen);
- break;
-
- case PrinterNameScan:
- *whichLen = (*instanceStateHdl)->printerName[0];
- BlockMove(&(*instanceStateHdl)->printerName[1], whichString, *whichLen);
- break;
-
- /*
- NilPtrScan entries have a length word which indicates a
- a length to pass to Munger along with the nil pointer.
- For these, get the length, move past that word, and set
- the appropriate string pointer to nil.
- */
- case NilPtrScan:
- *whichLen = *scanPtr;
- ++scanPtr;
-
- if (parsePass == 0)
- *str1Ptr = nil;
- else
- *str2Ptr = nil;
-
- break;
- }
- }
-
- // Get the entry's offset and action types, and move past those words.
-
- *offsetType = *scanPtr;
- ++scanPtr;
- *actionType = *scanPtr;
- ++scanPtr;
-
- /*
- If the action type is SimpleAction, get the status level,
- (Normal, NonFatalError, or FatalError), move past that
- word, get the 'stat' index to use, and move past that
- word as well.
- */
- if (*actionType == SimpleAction)
- {
- *statusLevel = *scanPtr;
- ++scanPtr;
- *statusIndex = *scanPtr;
- ++scanPtr;
- }
- else
- *statusLevel = *statusIndex = 0;
-
- // Update the passed 'scan' pointer, and return any errors.
-
- *scanPtrHolder = scanPtr;
- return err;
- }
-
-
- /* ______________________________________________________________
-
- MungeTheText -
-
- This routine finds and replaces text in our text handle, based
- on the results from our 'scan' parsing. It also returns true
- if the search string was found at least once.
-
- WHY THIS IS IMPORTANT:
-
- This code calls Munger to change the wording in our text
- handle, which may end up in the desktop printer window. It
- also tells us if keywords we're watching for in our 'scan'
- resource (like "cover open") are in the text handle.
-
- Briefly, text is munged as follows:
-
- SimpleOffset - Find or Replace 1st occurance of the
- ptr1 string.
-
- SameAsPreviousOffset - Insert the ptr2 text before the 1st
- occurance of the ptr1 string.
-
- ReturnedOffset - Insert the ptr2 text after the first
- occurance of the ptr1 string.
- SimpleRepeat,
- SameAsPreviousRepeat,
- ReturnedRepeat - Same as the above methods but apply
- repeatedly to entire text handle.
-
- Now, here's what Munger will do with the data it's passed, in
- the context of the above rules. (This Munger text comes from
- Inside Mac.)
-
- • If ptr1 is NIL, the substring of length len1 starting at
- the given offset is replaced by the replacement string. If
- len1 is negative, the substring from the given offset to
- the end of the destination string is replaced by the
- replacement string. In either case, Munger returns the
- offset of the first byte past where the replacement
- occurred.
-
- • If len1 is 0, (ptr2,len2) is simply inserted at the given
- offset; no text is replaced. Munger returns the offset of
- the first byte past where the insertion occurred.
-
- • If ptr2 is NIL, Munger returns the offset at which the
- target string was found. The destination string isn’t
- changed.
-
- • If len2 is 0 (and ptr2 is not NIL), the target string is
- deleted rather than replaced (since the replacement string
- is empty). Munger returns the offset at which the deletion
- occurred.
-
- ______________________________________________________________ */
-
- Boolean MungeTheText(short offsetType, Handle textHdl,
- void *ptr1, long len1,
- void *ptr2, long len2)
- {
- long handleSize, offset;
- Boolean found = false;
-
- /*
- The first longword of the text handle is the length of the
- text in it. Set the handle to that size (plus the length
- longword). Set our offset into the text handle to point
- after the length longword.
- */
- handleSize = *(long *) *textHdl;
- SetHandleSize(textHdl, handleSize +4);
- offset = 4;
- if (handleSize <= 0) return false;
-
-
- /*
- Based on the offsetType passed, do the appropriate munging.
- See the description in the function header for more info.
- */
- switch (offsetType)
- {
- case SimpleOffset: // replace the old occurances.
- case SimpleRepeat:
- do
- {
- offset = Munger(textHdl, offset, ptr1, len1, ptr2, len2);
- if (offset > 0) found = true;
- if (offset >= GetHandleSize(textHdl))
- offset = -1;
- }
- while ((offsetType == SimpleRepeat) && (offset > 0));
- break;
-
- case SameAsPreviousOffset: // insert just before the old occurances.
- case SameAsPreviousRepeat:
- do
- {
- offset = Munger(textHdl, offset, ptr1, len1, nil, 0);
- if (offset > 0)
- {
- found = true;
- offset = Munger(textHdl, offset, nil, 0, ptr2, len2);
- offset += len1;
- if (offset >= GetHandleSize(textHdl))
- offset = -1;
- }
- }
- while ((offsetType == SameAsPreviousRepeat) && (offset > 0));
- break;
-
- case ReturnedOffset: // insert just after the old occurances.
- case ReturnedRepeat:
- do
- {
- offset = Munger(textHdl, offset, ptr1, len1, nil, 0);
- if (offset > 0)
- {
- found = true;
- offset += len1;
- offset = Munger(textHdl, offset, nil, 0, ptr2, len2);
- if (offset > GetHandleSize(textHdl))
- offset = -1;
- }
- }
- while ((offsetType == ReturnedRepeat) && (offset > 0));
- break;
- }
-
- /*
- If we found a match, (and might have changed the text), reset
- the text size longword in the text handle.
- */
- if (found)
- *(long *) *textHdl = GetHandleSize(textHdl) -4;
-
- return found;
- }
-
-
- /* ______________________________________________________________
-
- SetAlertStatus -
-
- This routine calls GXAlertTheUser to display an alert, desktop
- printer message, to clear the alert status (by passing the
- printerReady code to GXAlertTheUser.
-
- WHY THIS IS IMPORTANT:
-
- This is the code that puts up and takes down dialogs, and
- clears the printer status based on our 'scan' handling results.
-
- ______________________________________________________________ */
-
- OSErr SetAlertStatus(short statResourceID, short statResourceIndex)
- {
- OSErr err = noErr;
- gxStatusRecord *statusPtr;
- DriverInstanceGlobalsHdl instanceStateHdl;
-
- // Retrieve our global data.
-
- instanceStateHdl = (DriverInstanceGlobalsHdl) GetMessageHandlerInstanceContext();
- require(instanceStateHdl, NoGlobalsSet);
- statusPtr = (*instanceStateHdl)->printStatus;
- require(statusPtr, NoGlobalsSet);
-
- /*
- Simply alert or update the dtp window based on what's
- in 'stat' ID = statResourceID, index = statResourceIndex.
- */
- statusPtr->statusType = 0;
- statusPtr->statusId = 0;
- statusPtr->statusAlertId = 0;
- statusPtr->statusOwner = kCreator;
- statusPtr->statResId = statResourceID;
- statusPtr->statResIndex = statResourceIndex;
- statusPtr->dialogResult = 0;
- statusPtr->bufferLen = gxDefaultStatusBufferSize;
-
- err = GXAlertTheUser(statusPtr);
-
- NoGlobalsSet:
- return err;
- }
-